#include "TcpClient.h"
#include <QTextCodec>
#include <QDebug>
#include <QEventLoop>

namespace CommonComponet
{
	TcpClient::TcpClient(QSharedPointer<CommonComponet::TcpConnectInfo> tcp_connect_info, DEVICE_CONN_TYPE tcpType,QString end_string,int timeout,int reconnect_timer, DataMode mode)
	{
		m_tcp_connect_info = tcp_connect_info;
		m_tcpSocket = NULL;
		m_tcp_state = CommonComponet::DeviceConnState::UnconnectedState;

		m_TcpType = tcpType;
		m_end_string = end_string;
		m_connect_server_time_out = timeout;
		m_reconnect_timer = reconnect_timer; //500ms reconnect...
		m_dataMode = mode;
	}

	TcpClient::~TcpClient() // other thread delete 
	{
		disconnect(this, nullptr, nullptr, nullptr);

		// 2. 停止并释放定时器
		if (m_timer) {
			m_timer->stop();
			m_timer->deleteLater();
			m_timer = nullptr;
		}


		if (m_tcpSocket == NULL)
			return;

		m_tcpSocket->disconnectFromHost();
		m_tcpSocket->abort();
		m_tcpSocket->deleteLater();
		m_tcpSocket = nullptr;

		/*
		m_tcpSocket->waitForDisconnected(m_connect_server_time_out);
		if (m_tcpSocket->state() == QAbstractSocket::UnconnectedState)
		{
			m_tcpSocket->abort();
		}
		*/
		 
	}

	void TcpClient::sendBinaryData(const QByteArray& data)
	{
		if (m_tcpSocket == NULL || data.isEmpty())
			return;

		if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
			return;

		m_tcpSocket->readAll(); // 清空缓冲区
		m_tcpSocket->write(data);
	}

	QByteArray TcpClient::sendAndWaitBinary(const QByteArray& data, int write_timeout, int read_timeout)
	{
		if (m_TcpType != SYNC_FAQ_WAIT || m_tcpSocket == NULL || data.isEmpty())
			return QByteArray();

		if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
			return QByteArray();

		QByteArray result;
		m_tcpSocket->readAll(); // 清空缓冲区
		m_tcpSocket->write(data);

		if (write_timeout <= 0) write_timeout = 3000;
		if (read_timeout <= 0) read_timeout = 3000;

		if (m_tcpSocket->waitForBytesWritten(write_timeout))
		{
			int totalTime = 0;
			int pertime = 100;

			while (m_tcpSocket != NULL && m_tcp_state == CommonComponet::DeviceConnState::ConnectedState)
			{
				result += m_tcpSocket->readAll();
				bool hasData = m_tcpSocket->waitForReadyRead(pertime);
				result += m_tcpSocket->readAll();

				if (!hasData)
				{
					if (totalTime >= read_timeout || !result.isEmpty())
						break;
				}

				totalTime += pertime;
				if (totalTime > read_timeout)
					break;
			}
		}

		return result;
	}

	void TcpClient::Started()
	{
		m_tcpSocket = new QTcpSocket(this);
		connect(m_tcpSocket, &QTcpSocket::stateChanged, this, &TcpClient::slot_SocketState);
		if (m_TcpType == ASYNC)
		{
			connect(m_tcpSocket, &QTcpSocket::readyRead, this, &TcpClient::slot_recvMessage);
		}

		qDebug() << __FUNCTION__ << "启动TCP 连接：ip：" << m_tcp_connect_info->ip << " port:" << m_tcp_connect_info->port;

		m_tcpSocket->connectToHost(m_tcp_connect_info->ip, m_tcp_connect_info->port);

		//event loopand the connected()
		
		if (m_tcpSocket->waitForConnected(m_connect_server_time_out))
		{
			m_tcpSocket->readAll();
		}

		m_timer = new QTimer(this);
		connect(m_timer, &QTimer::timeout, this, &TcpClient::updateTimer);
		m_timer->start(1000 * 60 * 3); // 3分钟检查一次
	}

	void TcpClient::updateTimer()
	{
		if (m_tcpSocket == NULL)
			return;

		if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
		{
			m_disconnect_time = m_disconnect_time + 3;
			qDebug() << __FUNCTION__ << " ip:" << m_tcp_connect_info->ip << " port:" << m_tcp_connect_info->port << " 失去连接。。。。" << m_tcpSocket->state();

			if (m_disconnect_time > 30)
			{
				m_timer->stop();
				m_timer->setInterval(1000 * 60 * 3 * 10); //10分钟检查一次
				m_timer->start();
			}
		}
		else 
		{
			//
		}
	}

	void TcpClient::slot_reconnect_server()
	{
		if (!m_tcpSocket || m_tcpSocket->state() == QAbstractSocket::HostLookupState
			|| m_tcpSocket->state() == QAbstractSocket::ConnectingState
			|| m_tcpSocket->state() == QAbstractSocket::ConnectedState
			|| m_tcpSocket->state() == QAbstractSocket::ClosingState)

			return;

		if (m_tcpSocket->state() == QAbstractSocket::UnconnectedState)
		{
			m_tcpSocket->connectToHost(m_tcp_connect_info->ip, m_tcp_connect_info->port);
		}
	}

	void TcpClient::slot_reconnect_server_by_newconfig(const QString& ip, int port)
	{
		if (m_tcpSocket == NULL)
			return;

		m_timer->stop();
		m_tcpSocket->disconnectFromHost();
		m_tcpSocket->abort();

		m_tcp_connect_info->ip = ip;
		m_tcp_connect_info->port = port;

		m_tcpSocket->connectToHost(m_tcp_connect_info->ip, m_tcp_connect_info->port);

		//event loopand the connected()

		if (m_tcpSocket->waitForConnected(m_connect_server_time_out))
		{
			m_tcpSocket->readAll();
		}
		m_timer->start(1000 * 60 * 3); // 3分钟检查一次
	}

	//questions and answers 
	QString TcpClient::slot_send_and_wait_message(QString message, int write_timeout, int read_timeout)
	{
		if (m_TcpType != SYNC_FAQ_WAIT)
			return "";

		if (m_tcpSocket == NULL)
			return "";

		if (message.isEmpty())
			return "";

		if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
			return "";

		QString result;

		m_tcpSocket->readAll();
		m_tcpSocket->write(message.toUtf8());

		if (write_timeout <= 0)
		{
			write_timeout = 3 * 1000;
		}

		if (m_tcpSocket->waitForBytesWritten(write_timeout))
		{
			QByteArray readData;
			int totalTime = 0;
			int pertime = 100;

			while (m_tcpSocket != NULL && m_tcp_state == CommonComponet::DeviceConnState::ConnectedState)
			{
				readData += m_tcpSocket->readAll();
				bool bsucc = m_tcpSocket->waitForReadyRead(pertime);
				readData += m_tcpSocket->readAll();

				if (!bsucc)
				{
					QString receive_message = QString(readData);
					if (m_end_string.isEmpty() == true)
					{
						result = receive_message;
						break;
					}

					int tag_index = receive_message.indexOf(m_end_string);
					if (tag_index > 0)
					{
						int length = receive_message.size() - tag_index + 1;
						result = receive_message.mid(0, length);
						break;
					}


					if (totalTime > read_timeout)
					{
						break;
					}
				}

				totalTime = totalTime + 100;
			}
		}
		else
		{
			qDebug() << __FUNCTION__ << " waitForBytesWritten time out:" << message;
		}

		return result;
	}

	void TcpClient::slot_async_timeout_send_message(QString message, int write_timeout, int read_timeout)
	{
		if (m_TcpType != ASYNC_AND_TIME_OUT)
			return;

		if (m_tcpSocket == NULL)
			return;

		if (message.isEmpty())
			return;

		if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
			return;

		m_tcpSocket->readAll();
		m_tcpSocket->write(message.toUtf8());
		if (m_tcpSocket->waitForBytesWritten(write_timeout))
		{
			if (m_tcpSocket->waitForReadyRead(read_timeout))
			{
				QByteArray readData = m_tcpSocket->readAll();
				emit sig_receiveDataFromServer(QString(readData).trimmed());
			}
			else
			{
				qDebug() << m_tcp_connect_info->ip << ":" << m_tcp_connect_info->port << " read信息超时：" << read_timeout << "ms";
				emit sig_receiveDataFromServer(QString(""));
			}
		}
		else
		{
			qDebug() << m_tcp_connect_info->ip << ":" << m_tcp_connect_info->port << " write信息超时：" << read_timeout << "ms";
			emit sig_receiveDataFromServer(QString(""));
		}
	}

	void TcpClient::slot_send_message(QString message)
	{
		if (m_TcpType != ASYNC)
			return;

		if (m_tcpSocket == NULL)
			return;

		if (message.isEmpty())
			return;

		if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
			return;

		m_tcpSocket->readAll();
		m_tcpSocket->write(message.toUtf8());
	}

	void TcpClient::slot_recvMessage()
	{
		if (m_tcpSocket == NULL)
			return;

		if (m_tcpSocket->state() != QAbstractSocket::ConnectedState)
			return;

		//event loopand the readyRead()

		m_tcpSocket->waitForReadyRead(100);
		QByteArray readData = m_tcpSocket->readAll();
		if (m_dataMode == BinaryMode)
		{
			// 二进制模式直接转发原始数据
			emit sig_receiveBinaryData(readData);
		}
		else {
			if (m_end_string.isEmpty() != true)
			{
				m_receive_string_package += QString(readData);

				while (true)
				{
					int tag_index = m_receive_string_package.indexOf(m_end_string);
					if (tag_index > 0)
					{
						QString one_message = m_receive_string_package.mid(0, tag_index + 1);
						emit sig_receiveDataFromServer(one_message.trimmed());

						m_receive_string_package = m_receive_string_package.mid(one_message.size() + m_end_string.size() - 1);
					}
					else
					{
						break;
					}
				}
			}
			else
			{
				m_receive_string_package.clear();
				emit sig_receiveDataFromServer(QString(readData).trimmed());
			}
		}
	}

	void TcpClient::slot_SocketState(QAbstractSocket::SocketState state)
	{
		if (state == QAbstractSocket::UnconnectedState)
		{
			m_tcp_state = CommonComponet::DeviceConnState::UnconnectedState;

			if (m_reconnect_timer > 0)
				QTimer::singleShot(m_reconnect_timer, this, &TcpClient::slot_reconnect_server);
		}
		else if (state == QAbstractSocket::ConnectedState)
		{
			m_tcp_state = CommonComponet::DeviceConnState::ConnectedState;
			m_tcpSocket->readAll(); //连接后清空缓冲区
		}

		emit sig_connection_state(m_tcp_state);
	}
}


